package gov.nasa.anml.lifted;

import java.util.ArrayList;

import gov.nasa.anml.PDDL;
import gov.nasa.anml.State;
import gov.nasa.anml.PDDL.Argument;
import gov.nasa.anml.PDDL.BooleanExpression;
import gov.nasa.anml.PDDL.Time;
import gov.nasa.anml.utility.SimpleObject;

public abstract class ExpressionImp<T, S extends SimpleObject<? super S>> implements Expression<T, S> {
	
	public static final void translateStmt(Expression<?,?> e, PDDL pddl, Interval unit, PDDL.Time time) {
		ArrayList<PDDL.BooleanExpression> conditions = unit.getPDDLConditions(); 
		if (e.typeCode() != TypeCode.Boolean) {
			System.err.println("Warning: Non-boolean expression-as-statement (i.e., a condition) found in: " + e);
			conditions.add(pddl.FalseCondition);
			return;
		}
		
		BooleanExpression b = (BooleanExpression)e.translateExpr(pddl,unit);
		if (e instanceof ConstantExpression<?>) {
			System.err.println("Someone should be calling the translateStmt that expects constants.");
			conditions.add(b);
			return;
		}
		
		translateStmt(b,pddl,unit,time);
	}

	public static final void translateStmt(PDDL.BooleanExpression b, PDDL pddl, Interval unit, PDDL.Time time) {
		ArrayList<PDDL.BooleanExpression> conditions = unit.getPDDLConditions(); 
		switch(time) {
		case Start:
		case End:
		case Interim:
			conditions.add(pddl.wrap(time,b));
			break;
		case All:
			conditions.add(pddl.wrap(PDDL.Time.Start,b));
		case EndHalf:
			conditions.add(pddl.wrap(PDDL.Time.Interim,b));
			conditions.add(pddl.wrap(PDDL.Time.End,b));
			break;
		case StartHalf:
			conditions.add(pddl.wrap(PDDL.Time.Start,b));
			conditions.add(pddl.wrap(PDDL.Time.Interim,b));
			break;
		case Timeless:
			conditions.add(b);
			break;
		default:
			System.err.println("New PDDL.Time constant unaccounted for in ExpressionImp.");
			conditions.add(pddl.FalseCondition);
		}
	}
		
	// keep the method signature the same besides the first argument so that the compiler can figure out which
	// to call without us having to think about it.
	public static final void translateStmt(ConstantExpression<?> e, PDDL pddl, Interval unit, PDDL.Time time) {
		ArrayList<PDDL.BooleanExpression> conditions = unit.getPDDLConditions(); 
		if (e.typeCode() != TypeCode.Boolean) {
			System.err.println("Warning: Non-boolean expression-as-statement (i.e., a condition) found in: " + e);
			conditions.add(pddl.FalseCondition);
			return;
		}
		
		BooleanExpression b = (BooleanExpression)e.translateExpr(pddl,unit);
		conditions.add(b);
	}
	

	public void translateDecl(PDDL pddl, Interval unit) {
		// expressions shouldn't have to be declaring anything.
	}
	
	public void translateStmt(PDDL pddl, Interval unit, PDDL.Time time) {
		translateStmt(this,pddl,unit,time);
	}
	
	// Very few things are valid PDDL arguments;
	public PDDL.Argument translateArgument(PDDL pddl, Interval unit) {
		//System.err.println("Someone is misusing ExpressionImp: " + this);
		return pddl.NullRef;
		// better than returning (java) null; allows us to get further without NPE.
	}
	
	// Likewise very few expressions have l-values.
	public PDDL.Expression translateLValue(PDDL pddl, Interval unit) {
		//System.err.println("Someone is misusing ExpressionImp: " + this);
		return pddl.TrueRef; 
		// ought to break most PDDL models.
		// better than returning null; allows us to get further without NPE.
	}

	public PDDL.Expression translateExpr(PDDL pddl, Interval unit) {
		//System.err.println("Someone is misusing ExpressionImp: " + this);
		return pddl.FalseRef;
	}
	


}

